/**
 * 自定义分词
 */
import {
  directus,
  getItems,
  createItem,
  updateItem,
  deleteItem,
  getItemById,
} from "../directus";

/** 集合名 */
export const COLLECTION_COSTOMWORDS = "costomwords" as const;
/** 导入 */
export const IMPORT_COSTOMWORDS_ENDPOINT = `/utils/import/${COLLECTION_COSTOMWORDS}` as const;

/** 状态 */
export type CustomWordStatus = "published" | "draft" | "archived";

/** 实体结构 */
export interface CustomWordItem {
  id: number | string;
  Original_word?: string;
  Processed_words?: string;
  status?: CustomWordStatus;
  date_created?: string;
  date_updated?: string;
}

/** 列表入参/返回 */
export interface CustomWordListParams {
  page?: number;
  pageSize?: number;
  keyword?: string;
  sort?: string | string[];
  excludeStatus?: CustomWordStatus | null;
  signal?: AbortSignal;
}
export interface CustomWordListResult {
  list: CustomWordItem[];
  total: number;
}

/** 导入结果 */
export interface CustomWordImportResult {
  total?: number;
  inserted?: number;
  created?: number;
  updated?: number;
  skipped?: number;
  failed?: number;
  details?: any;
}

/* ================================= 工具 ================================= */

const FIELDS_BASE = ["id", "Original_word", "Processed_words", "status"] as const;
type FieldKey = (typeof FIELDS_BASE)[number];

const normalizeSort = (sort?: string | string[]) =>
  Array.isArray(sort) ? sort.filter(Boolean) : sort ? [sort] : [];

const safeTrim = (s?: string) => (typeof s === "string" ? s.trim() : "");

const buildFilter = ({
  excludeStatus,
  keyword,
  ids,
}: {
  excludeStatus?: CustomWordStatus | null;
  keyword?: string;
  ids?: Array<number | string>;
}) => {
  const filter: Record<string, any> = {};
  if (excludeStatus) filter.status = { _neq: excludeStatus };
  const kw = safeTrim(keyword);
  if (kw) {
    filter._or = [
      { Original_word: { _contains: kw } },
      { Processed_words: { _contains: kw } },
    ];
  }
  if (ids && ids.length) filter.id = { _in: ids };
  return filter;
};

const timeStamp = () => {
  const d = new Date();
  const pad = (n: number) => String(n).padStart(2, "0");
  return `${d.getFullYear()}${pad(d.getMonth() + 1)}${pad(d.getDate())}-${pad(
    d.getHours()
  )}${pad(d.getMinutes())}${pad(d.getSeconds())}`;
};

const isBrowser = () =>
  typeof window !== "undefined" && typeof document !== "undefined";

const triggerDownload = (blob: Blob, filename: string) => {
  const url = URL.createObjectURL(blob);
  const a = document.createElement("a");
  a.href = url;
  a.download = filename;
  document.body.appendChild(a);
  a.click();
  a.remove();
  URL.revokeObjectURL(url);
};

function toCSV<T extends Record<string, any>>(
  rows: T[],
  headers: string[],
  opts?: { withBOM?: boolean }
) {
  const { withBOM = false } = opts || {};
  const escape = (val: any) => {
    const s = val == null ? "" : String(val);
    return /[",\n\r]/.test(s) ? `"${s.replace(/"/g, '""')}"` : s;
  };
  const lines: string[] = [];
  lines.push(headers.join(","));
  for (const r of rows) lines.push(headers.map((h) => escape((r as any)[h])).join(","));
  const content = lines.join("\r\n");
  return (withBOM ? "\uFEFF" : "") + content;
}

/** 简易 CSV 解析 */
function parseCSV(text: string): Record<string, string>[] {
  const rows: string[] = [];
  let cur = "";
  let inQ = false;
  for (let i = 0; i < text.length; i++) {
    const ch = text[i];
    const next = text[i + 1];
    if (ch === '"') {
      if (inQ && next === '"') {
        cur += '"';
        i++;
      } else {
        inQ = !inQ;
      }
    } else if ((ch === "\n" || ch === "\r") && !inQ) {
      if (cur.length) rows.push(cur);
      cur = "";
      if (ch === "\r" && next === "\n") i++;
    } else {
      cur += ch;
    }
  }
  if (cur.length) rows.push(cur);

  if (!rows.length) return [];
  const headers = rows[0].split(",").map((h) => h.replace(/^"|"$/g, "").trim());
  const out: Record<string, string>[] = [];
  for (let r = 1; r < rows.length; r++) {
    const cols: string[] = [];
    let cell = "";
    let q = false;
    for (let i = 0; i < rows[r].length; i++) {
      const ch = rows[r][i];
      const next = rows[r][i + 1];
      if (ch === '"') {
        if (q && next === '"') {
          cell += '"';
          i++;
        } else {
          q = !q;
        }
      } else if (ch === "," && !q) {
        cols.push(cell);
        cell = "";
      } else {
        cell += ch;
      }
    }
    cols.push(cell);
    const rec: Record<string, string> = {};
    headers.forEach((h, idx) => (rec[h] = (cols[idx] ?? "").replace(/^"|"$/g, "")));
    out.push(rec);
  }
  return out;
}

/* ======================= 列表 / 详情 / 新增 / 更新 / 删除 ======================= */

export async function fetchCustomWordList(
  params: CustomWordListParams = {}
): Promise<CustomWordListResult> {
  const {
    page = 1,
    pageSize = 25,
    keyword = "",
    sort = ["id"],
    excludeStatus = "archived",
    signal,
  } = params;

  const res: any = await getItems<CustomWordItem>(COLLECTION_COSTOMWORDS, {
    limit: pageSize,
    page,
    fields: FIELDS_BASE as unknown as FieldKey[],
    sort: normalizeSort(sort),
    filter: buildFilter({ excludeStatus, keyword }),
    meta: "filter_count",
    signal,
  });

  const list: CustomWordItem[] = Array.isArray(res?.data) ? res.data : res || [];
  const total: number = Number(res?.meta?.filter_count ?? res?.meta?.total_count ?? list.length);
  return { list, total };
}

/** 详情 */
export async function getCustomWordById(
  id: number | string,
  fields: string[] = [
    "id",
    "Original_word",
    "Processed_words",
    "status",
    "date_created",
    "date_updated",
  ]
) {
  const res: any = await getItemById(COLLECTION_COSTOMWORDS, id, { fields });
  return res?.data ?? res;
}

/** 新增 */
export async function createCustomWord(payload: {
  Original_word: string;
  Processed_words: string;
  status?: CustomWordStatus;
}) {
  const data = {
    Original_word: (payload.Original_word ?? "").trim(),
    Processed_words: (payload.Processed_words ?? "").trim(),
    status: (payload.status ?? "published") as CustomWordStatus,
  };
  const res: any = await createItem(COLLECTION_COSTOMWORDS, data);
  return res?.data ?? res;
}

/** 更新 */
export async function updateCustomWord(
  id: number | string,
  patch: Partial<Pick<CustomWordItem, "Original_word" | "Processed_words" | "status">>
) {
  const body: any = {};
  if (patch.Original_word != null) body.Original_word = String(patch.Original_word).trim();
  if (patch.Processed_words != null) body.Processed_words = String(patch.Processed_words).trim();
  if (patch.status != null) body.status = patch.status;
  const res: any = await updateItem(COLLECTION_COSTOMWORDS, id, body);
  return res?.data ?? res;
}

/** 单删 */
export async function removeCustomWord(id: number | string) {
  const res: any = await deleteItem(COLLECTION_COSTOMWORDS, id);
  return res?.data ?? res;
}

/** 批量删 */
export async function batchRemoveCustomWords(ids: Array<number | string>) {
  if (!ids?.length) return;
  try {
    await directus.delete(`/items/${COLLECTION_COSTOMWORDS}`, {
      headers: { "Content-Type": "application/json" },
      data: { keys: ids },
    });
  } catch {
    await Promise.all(ids.map((id) => deleteItem(COLLECTION_COSTOMWORDS, id)));
  }
}

/* ======================= 启用 / 停用 ======================= */

export function enableCustomWord(id: number | string) {
  return updateCustomWord(id, { status: "published" });
}
export function disableCustomWord(id: number | string) {
  return updateCustomWord(id, { status: "draft" });
}

/* ======================= 导出 ======================= */

export type ExportFormat = "csv" | "json";
export interface ExportParams extends Partial<CustomWordListParams> {
  format: ExportFormat;
  selectedIds?: Array<number | string>;
  filename?: string;
  autoDownload?: boolean;
}

export async function exportCustomWords(p: ExportParams) {
  const {
    format,
    selectedIds = [],
    filename = `custom-words-${timeStamp()}`,
    autoDownload = true,
    keyword = "",
    sort = ["id"],
    excludeStatus = "archived",
    signal,
  } = p;

  if (!format) throw new Error("exportCustomWords: 缺少导出格式 format");

  const filter = buildFilter({
    excludeStatus,
    keyword: selectedIds.length ? undefined : keyword,
    ids: selectedIds.length ? selectedIds : undefined,
  });

  const res: any = await getItems(COLLECTION_COSTOMWORDS, {
    limit: -1,
    page: 1,
    fields: ["Original_word", "Processed_words", "status"],
    sort: normalizeSort(sort),
    filter,
    signal,
  });

  const rows: Array<Pick<CustomWordItem, "Original_word" | "Processed_words" | "status">> = (
    Array.isArray(res?.data) ? res.data : res || []
  ).map((it: any) => ({
    Original_word: it?.Original_word ?? "",
    Processed_words: it?.Processed_words ?? "",
    status: it?.status ?? "",
  }));

  const headers = ["Original_word", "Processed_words", "status"];
  let blob: Blob, fullName: string;

  if (format === "csv") {
    const csv = toCSV(rows, headers, { withBOM: true });
    blob = new Blob([csv], { type: "text/csv;charset=utf-8" });
    fullName = `${filename}.csv`;
  } else {
    const json = JSON.stringify(rows, null, 2);
    blob = new Blob([json], { type: "application/json;charset=utf-8" });
    fullName = `${filename}.json`;
  }

  if (autoDownload && isBrowser()) triggerDownload(blob, fullName);
  return { blob, filename: fullName, total: rows.length, headers, rows };
}

/* ======================= 导入 ======================= */
export async function importCustomWordsByFile(
  file: File | Blob,
  extra?: { format?: "csv" | "json"; overwrite?: boolean; signal?: AbortSignal; filename?: string; chunkSize?: number }
): Promise<CustomWordImportResult> {
  if (!file) throw new Error("请选择要导入的文件");
  try {
    const fd = new FormData();
    const name = extra?.filename || (file instanceof File ? file.name : `${COLLECTION_COSTOMWORDS}.csv`);
    fd.append("file", file, name);
    if (extra?.format) fd.append("format", extra?.format);
    if (typeof extra?.overwrite === "boolean") fd.append("overwrite", String(extra.overwrite));

    const res: any = await directus.post(IMPORT_COSTOMWORDS_ENDPOINT, fd, {
      signal: extra?.signal as any,
      withCredentials: true,
    });
    return (res?.data?.data ?? res?.data) as CustomWordImportResult;
  } catch (err: any) {
    const status = err?.response?.status;
    if (![400, 404, 409, 413, 415, 422].includes(Number(status))) {
      throw err;
    }
    if (!(file instanceof File)) throw err;
    const text = await file.text();
    let items: Array<{ Original_word: string; Processed_words: string; status?: CustomWordStatus }> = [];
    const lower = (extra?.format || (file.name.split(".").pop() || "")).toLowerCase();
    if (lower === "json") {
      const raw = JSON.parse(text);
      if (Array.isArray(raw)) {
        items = raw.map((r: any) => ({
          Original_word: String(r?.Original_word ?? "").trim(),
          Processed_words: String(r?.Processed_words ?? "").trim(),
          status: (r?.status ?? "published") as CustomWordStatus,
        }));
      }
    } else {
      const rows = parseCSV(text);
      items = rows.map((r) => ({
        Original_word: String(r?.Original_word ?? "").trim(),
        Processed_words: String(r?.Processed_words ?? "").trim(),
        status: (r?.status ?? "published") as CustomWordStatus,
      }));
    }
    items = items.filter((it) => it.Original_word || it.Processed_words);
    if (!items.length) {
      throw new Error("导入文件解析为空：请确认包含列 Original_word / Processed_words / status");
    }
    // 分片批量写入
    const chunkSize = extra?.chunkSize && extra.chunkSize > 0 ? extra.chunkSize : 200;
    let created = 0;
    for (let i = 0; i < items.length; i += chunkSize) {
      const slice = items.slice(i, i + chunkSize);
      const res = await directus.post(`/items/${COLLECTION_COSTOMWORDS}`, slice, {
        signal: extra?.signal as any,
      });
      const ok = Array.isArray(res?.data?.data) ? res.data.data.length : slice.length;
      created += ok;
    }

    return { total: items.length, created };
  }
}

/** 直接传 items 导入 */
export async function importCustomWordsByItems(
  items: Array<{ Original_word: string; Processed_words: string; status?: CustomWordStatus }>,
  extra?: { overwrite?: boolean; signal?: AbortSignal; chunkSize?: number }
): Promise<CustomWordImportResult> {
  if (!Array.isArray(items) || !items.length) {
    throw new Error("items 不能为空");
  }
  try {
    const body = { items, overwrite: extra?.overwrite ?? undefined };
    const res: any = await directus.post(IMPORT_COSTOMWORDS_ENDPOINT, body, {
      signal: extra?.signal as any,
    });
    return (res?.data?.data ?? res?.data) as CustomWordImportResult;
  } catch (err: any) {
    const status = err?.response?.status;
    if (![400, 404, 409, 413, 415, 422].includes(Number(status))) {
      throw err;
    }
    const chunkSize = extra?.chunkSize && extra.chunkSize > 0 ? extra.chunkSize : 200;
    let created = 0;
    for (let i = 0; i < items.length; i += chunkSize) {
      const slice = items.slice(i, i + chunkSize);
      const res = await directus.post(`/items/${COLLECTION_COSTOMWORDS}`, slice, {
        signal: extra?.signal as any,
      });
      const ok = Array.isArray(res?.data?.data) ? res.data.data.length : slice.length;
      created += ok;
    }
    return { total: items.length, created };
  }
}
